package com.aimls.base64;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.apache.commons.codec.binary.Base64;

/**
 * 
 * 对文件进行Base64编码.该功能使用org.apache.commons.codec包实现，没有使用sun.misc包
 * <p>
 * -----------------------------------------------------------------------------
 * <p>
 * 工程名 ： UDE
 * <p>
 * 授权 : (C) Copyright topwalk Corporation 2006-2011
 * <p>
 * 公司 : 北京天行网安信息技术有限责任公司
 * <p>
 * -----------------------------------------------------------------------------
 * <p>
 * <font color="#FF0000">注意: 本内容仅限于北京天行网安公司内部使用，禁止转发</font>
 * <p>
 * 
 * @version 1.0
 * @author zhangyx
 * @createdate 2011-9-3
 * @since JDK1.6
 */
public class FileBase64 {

	/**
	 * 读取一次文件使用使用的缓冲区大小
	 */
	private static int bufferSize = 57;


	/**
	 * 文件进行Base64编码
	 * 
	 * @param sourceFile
	 *            源文件
	 * @param encodeFile
	 *            编码后的文件
	 * @param isNewLine
	 *            每次编码后是否进行换行
	 * @throws Exception
	 *             出现的异常
	 */
	public static void encodeFile(String sourceFile, String encodeFile,
			boolean isNewLine) throws Exception {
		// 判断参数是否为null
		if ((sourceFile == null) || (encodeFile == null)) {
			throw new Exception("参数为null");
		}
		File file = new File(sourceFile);
		File fileNew = new File(encodeFile);
		// 判断源文件是否存在
		if (!file.isFile()) {
			throw new Exception("源文件不存在");
		}
		FileInputStream is = null;
		FileOutputStream out = null;
		try {
			is = new FileInputStream(file);
			out = new FileOutputStream(fileNew);
			byte[] buffer = new byte[bufferSize];
			int length = 0;
			// 读取文件
			while ((length = is.read(buffer)) != -1) {
				// 判断是否到达文件末尾
				if (length < bufferSize) {
					// 达到文件尾，需要把多读出的数据清除掉
					byte[] newBuffer = Arrays.copyOf(buffer, length);
					// 进行编码并写入文件
					out.write(Base64.encodeBase64(newBuffer));
				} else {
					// 进行编码并写入文件
					out.write(Base64.encodeBase64(buffer));
					// 在一行输出完成后需要添加一行换行
					if (isNewLine)
						out.write("\n".getBytes());
				}
			}
		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
			}
			try {
				if (out != null)
					out.close();
			} catch (IOException e) {
			}
		}

	}

	/**
	 * 对已经Base64编码后的文件进行解码
	 * 
	 * @param sourceFile
	 *            编码后的文件
	 * @param decodeFile
	 *            解码后的文件
	 * @param isNewLine
	 *            每次编码后是否进行换行，需要和加密相对应
	 * @throws Exception
	 *             出现的异常
	 */
	public static void decodeFile(String sourceFile, String decodeFile,
			boolean isNewLine) throws Exception {
		if ((sourceFile == null) || (decodeFile == null)) {
			throw new Exception("参数为null");
		}
		File file = new File(sourceFile);
		File fileNew = new File(decodeFile);
		if (!file.isFile()) {
			throw new Exception("源文件不存在");
		}

		FileInputStream is = null;
		FileOutputStream out = null;

		try {
			is = new FileInputStream(file);
			out = new FileOutputStream(fileNew);
			// 获取每次读出的行数，根据base64规则，解密时读出的大小，应该是写入时的3分之4
			int readBufferSize = (bufferSize * 4 / 3);
			// 如果编码前换行了，需要多读出一个字符
			if (isNewLine)
				readBufferSize = readBufferSize + 1;

			byte[] buffer = new byte[readBufferSize];
			int length = 0;

			// 逐次进行解码
			while ((length = is.read(buffer)) != -1) {
				// 判断是否文件末尾
				if (length < readBufferSize) {
					// 进行编码
					out.write(Base64
							.decodeBase64(new String(buffer, 0, length)));
				} else {
					// 如果不是末尾，需要判断isNewLine
					if (isNewLine)
						out.write(Base64.decodeBase64(new String(buffer, 0,
								length - 1)));
					else
						out.write(Base64.decodeBase64(new String(buffer, 0,
								length)));
				}
			}
		} catch (Exception e) {
			throw e;
		} finally {

			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
			}
			try {
				if (out != null)
					out.close();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * 文件进行Base64编码。 使用是注意文件的大小，因为所有数据在内存中，使用不当可能导致内存溢出
	 * 
	 * @param sourceFile
	 *            编码后源文件
	 * @param isNewLine
	 *            每次编码后是否进行换行
	 * @return 编码后的字符串
	 * @throws Exception
	 *             出现的异常
	 */
	public static String encodeFile(String sourceFile, boolean isNewLine)
			throws Exception {
		// 判断参数是否为null
		if ((sourceFile == null)) {
			throw new Exception("参数为null");
		}
		File file = new File(sourceFile);
		// 判断源文件是否存在
		if (!file.isFile()) {
			throw new Exception("源文件不存在");
		}
		FileInputStream is = null;
		StringBuffer sb = new StringBuffer();
		try {
			is = new FileInputStream(file);
			byte[] buffer = new byte[bufferSize];
			int length = 0;
			// 读取文件
			while ((length = is.read(buffer)) != -1) {
				// 判断是否到达文件末尾
				if (length < bufferSize) {
					// 达到文件尾，需要把多读出的数据清除掉
					byte[] newBuffer = Arrays.copyOf(buffer, length);
					// 进行编码并写入文件
					sb.append(new String(Base64.encodeBase64(newBuffer)));
				} else {
					// 进行编码并写入文件
					sb.append(new String(Base64.encodeBase64(buffer)));
					// 在一行输出完成后需要添加一行换行
					if (isNewLine)
						sb.append("\n");
				}
			}
		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
			}
		}
		return sb.toString();

	}

	/**
	 * 对已经Base64编码后的文件进行还原，使用是注意文件的大小，因为所有数据在内存中，使用不当可能导致内存溢出
	 * 
	 * @param sourceFile
	 *            编码后源文件
	 * @param isNewLine
	 *            每次编码后是否进行换行
	 * @return 解码后的字符串
	 * @throws Exception
	 *             出现的异常
	 */
	public static String decodeFile(String sourceFile, boolean isNewLine)
			throws Exception {
		if (sourceFile == null) {
			throw new Exception("参数为null");
		}
		File file = new File(sourceFile);
		if (!file.isFile()) {
			throw new Exception("源文件不存在");
		}

		FileInputStream is = null;
		StringBuffer sb = new StringBuffer();
		try {
			is = new FileInputStream(file);
			// 获取每次读出的行数，根据base64规则，解密时读出的大小，应该是写入时的3分之4
			int readBufferSize = (bufferSize * 4 / 3);
			// 如果编码前换行了，需要多读出一个字符
			if (isNewLine)
				readBufferSize = readBufferSize + 1;

			byte[] buffer = new byte[readBufferSize];
			int length = 0;

			// 逐次进行解码
			while ((length = is.read(buffer)) != -1) {
				// 判断是否文件末尾
				if (length < readBufferSize) {
					// 进行编码
					sb.append(new String(Base64.decodeBase64(new String(buffer,
							0, length))));
				} else {
					// 如果不是末尾，需要判断isNewLine
					if (isNewLine)
						sb.append(new String(Base64.decodeBase64(new String(
								buffer, 0, length - 1))));
					else
						sb.append(new String(Base64.decodeBase64(buffer)));
				}
			}
		} catch (Exception e) {
			throw e;
		} finally {

			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
			}
		}
		return sb.toString();
	}
}